package main

//起别名： 别名 包名
//如果使用包的初始化或接口实现，并没有明显调用  需要使用_来区分
import (
	"fmt"
	"reflect"
	"time"
)

/*
	命名规则：
		1.允许使用字母、数字、下划线
		2.区分大小写
		3.不允许使用数字开头
		4.不允许使用系统关键字
		5.见名知义
	驼峰命名：
		小驼峰：第一个单词小写后面每个单词的首字母大写
		大驼峰：所有单词首字母都已大写开头
		ps:在go当中以小驼峰命名一般都表示只允许内部调用，大驼峰允许外部调用
*/

func main01() {
	//定义变量
	//var 变量名 数据类型 = 值
	//var a int = 10
	//var b = 20
	//自动推导类型
	//c := 30
	//多重赋值
	a, b, c := 1, true, "瞅啥"
	//使用多重赋值来完成变量的交换
	a1 := 123
	a2 := 666
	a1, a2 = a2, a1

	fmt.Println(a)
	fmt.Println(b)
	fmt.Println(c)

	fmt.Println(a1, a2)

	fmt.Printf("%T\n", a)
	fmt.Printf("%T\n", b)
	fmt.Printf("%T\n", c)
}

func main02() {
	//a := 100
	//一般建议常量名大写
	//const PI = 3.1415926
	//const MAX = 100

	//在go中 常量不允许寻址
	//&取地址运算符
	//fmt.Println(&a)
	//fmt.Println(&PI)

	//iota常量集 枚举enum
	/*const(
		a = iota
		b = iota
		c
		d
		e
	)*/

	const (
		a = 123
		b = true
		c = "瞅瞅你"
		d = 3.15444
	)
	fmt.Println(a, b, c, d)
}

//函数的格式
/*
func 函数名(参数,参数……)(返回值列表){
	代码体
	返回值
}
*/
func main03() {
	//demo.Test()
	//匿名函数  必须在函数内部定义
	//func 函数名(参数,参数……)(返回值列表){
	//}()

	//函数类型变量
	//使用等号赋值时，变量必须是函数类型，参数类型必须一致
	function := func(a int, b int) {
		fmt.Println(a + b)
	}
	function(10, 20)
	fmt.Printf("%T\n", function)
}

//为函数定义类型
type FUNCTYPE func(int, bool, string)

func demo(a int, b bool, c string) {
	fmt.Println("傻篮子")
}

//函数回调
func demo2(f FUNCTYPE) {
	f(1, false, "")
}
func main04() {
	//type
	//1、为数据类型起别名
	//2、为函数定义类型
	//type i8 int8//如果没有等号  不允许计算
	type i8 = int8 //如果有等号  允许计算
	var a i8 = 123
	var b int8 = 2
	fmt.Println(a + b) //invalid operation: a + b (mismatched types i8 and int8)

	//byte 字符类型
	var ch byte = 'a'
	fmt.Println(ch)

	var f FUNCTYPE
	f = demo
	//f(1,false,"aaa")
	demo2(f)
}

func main05() {
	//空接口类型 可以接收任意类型数据、
	var a interface{}
	a = 123
	a = "hello"
	fmt.Println(a)
	//var b interface{} = 456
	//接口数据不允许计算
	//fmt.Println(a+b) //invalid operation: a + b (operator + not defined on interface)
	//通过反射获取空接口对应的数据类型
	t := reflect.TypeOf(a)
	fmt.Println(t)
	//通过反射获取空接口对应的值
	v := reflect.ValueOf(a)
	fmt.Println(v)
	fmt.Printf("%T\n", v) //reflect.Value类型
	//接口类型断言获取值，值的类型会被转换为值对应的类型
	v1, ok := a.(int)
	fmt.Println(v1, ok)
	fmt.Printf("%T %T\n", v1, ok)
}

//结构体定义
type Student struct {
	id      int
	sex     string
	age     int
	name    string
	address string
}

func main06() {
	//结构体初始化
	var stu Student
	//结构体变量.成员
	stu.id = 1001
	stu.sex = "男"
	stu.age = 10
	stu.name = "你好"
	stu.address = "地址"
	fmt.Println(stu)
}

func main07() {
	//创建一个空的 map，空map不能存储任何数据
	//var m1 map[int]string //默认值为nil
	//m[1001] = "你好"
	//fmt.Println(m)//panic: assignment to entry in nil map
	//map中的key的类型不能是 函数 字段 切片
	m2 := make(map[int]string)
	m2[1001] = "你好1"
	m2[1002] = "你好2"
	m2[1003] = "你好3"
	m2[1004] = "你好4"
	//fmt.Println(m2,m1)
	//map中的数据是无序的
	for k , v := range m2  {
		fmt.Println(k,v)
	}

}

func main08(){
	fmt.Println("hello")
	go func(){
		fmt.Println("hello world")
	}()
	time.Sleep(time.Second * 3)
}

func main09(){
	/*
		if 表达式{
			代码块
		}else{
			代码块
		}
	*/
	//1、在switch 中 case值 不允许是浮点类型 （因为浮点型是相对精准）
	//2、如果多个值执行相同内容 可以使用逗号分隔
	//3、不需要在switch中使用break
	/*var value float64
	switch value {
		case 3.1415:
	}*/
	var m int
	fmt.Scan(&m)
	switch m {
		case 1,3,5,7,8,10,12:
			fmt.Println(31)
			fallthrough //让当前case向下执行
		case 4,6,9,11:
			fmt.Println(30)
		case 2:
			fmt.Println("28 or 29")
	}
}

func main(){
	for i := 0; i < 10; i++ {
		fmt.Println(i)
		break //结束循环
		continue //跳出本次循环执行下次循环
	}
	/*for key, value := range array  {

	}*/

	//goto 标识符建议大写
	fmt.Println(1)
	goto FLAG
	fmt.Println(2)
	fmt.Println(3)
	FLAG:
	fmt.Println(4)

	//在程序执行完成之后，进行内存释放时依次从后往前执行defer
	defer fmt.Println(5)
	fmt.Println(6)
	defer fmt.Println(7)
	defer fmt.Println(8)
}
